using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using CollabApp.Domain.Entities.Game;
using CollabApp.Domain.Entities.Room;
using CollabApp.Domain.Entities.Auth;
using CollabApp.Domain.Repositories;
using CollabApp.Domain.Services.Game;
using CollabApp.Domain.Services.Room;
using System.Security.Claims;

namespace CollabApp.API.Hubs;

/// <summary>
/// 游戏实时通信Hub - 处理画线圈地游戏的实时交互
/// 提供玩家移动、绘制、状态同步等实时功能，严格按照业务规则实现
/// </summary>
public class GameHub : Hub
{
    private readonly IRepository<Game> _gameRepository;
    private readonly IRepository<GamePlayer> _gamePlayerRepository;
    private readonly IRepository<GameAction> _gameActionRepository;
    private readonly IRepository<Room> _roomRepository;
    private readonly IRepository<RoomPlayer> _roomPlayerRepository;
    private readonly IRepository<User> _userRepository;
    private readonly IPlayerStateService _playerStateService;
    private readonly IGamePlayService _gamePlayService;
    private readonly ISpecialEventService _specialEventService;
    private readonly IDynamicBalanceService _dynamicBalanceService;
    private readonly IMapShrinkingService _mapShrinkingService;
    private readonly IRoomService _roomService;
    private readonly ILogger<GameHub> _logger;

    public GameHub(
        IRepository<Game> gameRepository,
        IRepository<GamePlayer> gamePlayerRepository,
        IRepository<GameAction> gameActionRepository,
        IRepository<Room> roomRepository,
        IRepository<RoomPlayer> roomPlayerRepository,
        IRepository<User> userRepository,
        IPlayerStateService playerStateService,
        IGamePlayService gamePlayService,
        ISpecialEventService specialEventService,
        IDynamicBalanceService dynamicBalanceService,
        IMapShrinkingService mapShrinkingService,
        IRoomService roomService,
        ILogger<GameHub> logger)
    {
        _gameRepository = gameRepository;
        _gamePlayerRepository = gamePlayerRepository;
        _gameActionRepository = gameActionRepository;
        _roomRepository = roomRepository;
        _roomPlayerRepository = roomPlayerRepository;
        _userRepository = userRepository;
        _playerStateService = playerStateService;
        _gamePlayService = gamePlayService;
        _specialEventService = specialEventService;
        _dynamicBalanceService = dynamicBalanceService;
        _mapShrinkingService = mapShrinkingService;
        _roomService = roomService;
        _logger = logger;
    }

    /// <summary>
    /// 玩家加入游戏房间
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="playerId">玩家ID</param>
    public async Task JoinGameRoom(Guid gameId, Guid playerId)
    {
        try
        {
            // 验证游戏是否存在且可加入
            var game = await _gameRepository.GetByIdAsync(gameId);
            if (game == null)
            {
                await Clients.Caller.SendAsync("Error", "游戏不存在");
                return;
            }

            if (game.Status != GameStatus.Preparing && game.Status != GameStatus.Playing)
            {
                await Clients.Caller.SendAsync("Error", "游戏状态不允许加入");
                return;
            }

            // 验证玩家是否在游戏中 - 使用UserId而不是PlayerId
            var gamePlayer = (await _gamePlayerRepository.GetAllAsync())
                .FirstOrDefault(gp => gp.GameId == gameId && gp.UserId == playerId);
            
            if (gamePlayer == null)
            {
                await Clients.Caller.SendAsync("Error", "玩家未参与此游戏");
                return;
            }

            // 获取玩家实时状态
            var playerState = await _playerStateService.GetPlayerStateAsync(gameId, playerId);
            if (playerState == null)
            {
                await Clients.Caller.SendAsync("Error", "无法获取玩家状态");
                return;
            }

            // 加入SignalR组
            var groupName = $"game_{gameId}";
            await Groups.AddToGroupAsync(Context.ConnectionId, groupName);

            // 通知房间内其他玩家
            await Clients.Group(groupName).SendAsync("PlayerJoined", new
            {
                PlayerId = playerId,
                PlayerName = playerState.PlayerName,
                PlayerColor = playerState.PlayerColor,
                ConnectionId = Context.ConnectionId,
                JoinedAt = DateTime.UtcNow
            });

            // 发送当前游戏状态给新加入的玩家
            var gameStates = await _playerStateService.GetAllPlayerStatesAsync(gameId);
            
            await Clients.Caller.SendAsync("GameState", new
            {
                GameId = gameId,
                Status = game.Status.ToString(),
                Players = gameStates.Select(p => new
                {
                    p.PlayerId,
                    p.PlayerName,
                    p.PlayerColor,
                    Position = p.CurrentPosition,
                    Territory = p.TotalTerritoryArea,
                    State = p.State.ToString(),
                    CurrentTrail = p.CurrentTrail,
                    IsInvulnerable = p.IsInvulnerable,
                    InvulnerabilityEndTime = p.InvulnerabilityEndTime,
                    Inventory = p.Inventory,
                    Rank = p.CurrentRank
                }).ToList(),
                StartedAt = game.StartedAt,
                FinishedAt = game.FinishedAt
            });

            _logger.LogInformation("玩家 {PlayerId} 加入游戏 {GameId} 的实时房间", playerId, gameId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "玩家加入游戏房间时发生错误: GameId={GameId}, PlayerId={PlayerId}", gameId, playerId);
            await Clients.Caller.SendAsync("Error", "加入游戏房间失败");
        }
    }

    /// <summary>
    /// 玩家离开游戏房间
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="playerId">玩家ID</param>
    public async Task LeaveGameRoom(Guid gameId, Guid playerId)
    {
        try
        {
            var groupName = $"game_{gameId}";
            await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);

            // 通知房间内其他玩家
            await Clients.Group(groupName).SendAsync("PlayerLeft", new
            {
                PlayerId = playerId,
                ConnectionId = Context.ConnectionId,
                LeftAt = DateTime.UtcNow
            });

            _logger.LogInformation("玩家 {PlayerId} 离开游戏 {GameId} 的实时房间", playerId, gameId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "玩家离开游戏房间时发生错误: GameId={GameId}, PlayerId={PlayerId}", gameId, playerId);
        }
    }

    /// <summary>
    /// 玩家移动 - 使用完整的业务逻辑和Position类型
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="playerId">玩家ID</param>
    /// <param name="newPosition">新位置</param>
    /// <param name="isDrawing">是否正在绘制</param>
    public async Task PlayerMove(Guid gameId, Guid playerId, Position newPosition, bool isDrawing)
    {
        try
        {
            // 验证游戏状态
            var game = await _gameRepository.GetByIdAsync(gameId);
            if (game?.Status != GameStatus.Playing)
            {
                await Clients.Caller.SendAsync("Error", "游戏未进行中");
                return;
            }

            // 验证玩家是否在游戏中
            var gamePlayer = (await _gamePlayerRepository.GetAllAsync())
                .FirstOrDefault(gp => gp.GameId == gameId && gp.UserId == playerId);
            
            if (gamePlayer == null)
            {
                await Clients.Caller.SendAsync("Error", "玩家不在游戏中");
                return;
            }

            // 获取当前玩家状态
            var currentState = await _playerStateService.GetPlayerStateAsync(gameId, playerId);
            if (currentState == null || currentState.State == PlayerDrawingState.Dead)
            {
                await Clients.Caller.SendAsync("Error", "玩家状态异常或已死亡");
                return;
            }

            // 调用领域服务更新位置
            var moveResult = await _playerStateService.UpdatePlayerPositionAsync(
                gameId, playerId, newPosition, DateTime.UtcNow, isDrawing);
            
            if (!moveResult.Success)
            {
                await Clients.Caller.SendAsync("MoveRejected", new
                {
                    PlayerId = playerId,
                    Reason = string.Join("; ", moveResult.Errors),
                    OldPosition = moveResult.OldPosition,
                    Timestamp = DateTime.UtcNow
                });
                return;
            }

            // 记录移动动作
            var moveAction = GameAction.CreateMoveAction(
                gameId: gameId,
                userId: playerId,
                x: (decimal)moveResult.NewPosition.X,
                y: (decimal)moveResult.NewPosition.Y,
                speed: (decimal)moveResult.CurrentSpeed,
                inEnemyTerritory: false,
                timestamp: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            );

            await _gameActionRepository.AddAsync(moveAction);

            // 如果正在画线，开始或继续绘制
            if (isDrawing && currentState.State == PlayerDrawingState.Idle)
            {
                var drawingResult = await _playerStateService.StartDrawingAsync(gameId, playerId, newPosition);
                if (!drawingResult.Success)
                {
                    _logger.LogWarning("玩家 {PlayerId} 开始绘制失败: {Errors}", 
                        playerId, string.Join("; ", drawingResult.Errors));
                }
            }

            // 实时广播给房间内所有玩家
            var groupName = $"game_{gameId}";
            var broadcastData = new
            {
                PlayerId = playerId,
                Position = moveResult.NewPosition,
                OldPosition = moveResult.OldPosition,
                Speed = moveResult.CurrentSpeed,
                DistanceMoved = moveResult.DistanceMoved,
                IsDrawing = isDrawing,
                Events = moveResult.Events,
                Timestamp = DateTime.UtcNow
            };

            await Clients.Group(groupName).SendAsync("PlayerMoved", broadcastData);

            // 如果有碰撞事件，特殊处理
            if (moveResult.CollisionDetected && moveResult.CollisionInfo != null)
            {
                await HandleCollisionEventAsync(gameId, playerId, moveResult.CollisionInfo);
            }

            _logger.LogDebug("玩家 {PlayerId} 在游戏 {GameId} 中移动: {OldPos} -> {NewPos}, 速度: {Speed}",
                playerId, gameId, moveResult.OldPosition, moveResult.NewPosition, moveResult.CurrentSpeed);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "玩家移动时发生错误: GameId={GameId}, PlayerId={PlayerId}", gameId, playerId);
            await Clients.Caller.SendAsync("Error", "移动失败");
        }
    }

    /// <summary>
    /// 玩家完成路径绘制
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="playerId">玩家ID</param>
    public async Task CompleteDrawing(Guid gameId, Guid playerId)
    {
        try
        {
            // 验证游戏状态
            var game = await _gameRepository.GetByIdAsync(gameId);
            if (game?.Status != GameStatus.Playing)
            {
                await Clients.Caller.SendAsync("Error", "游戏未进行中");
                return;
            }

            // 验证玩家是否在游戏中
            var gamePlayer = (await _gamePlayerRepository.GetAllAsync())
                .FirstOrDefault(gp => gp.GameId == gameId && gp.UserId == playerId);
            
            if (gamePlayer == null)
            {
                await Clients.Caller.SendAsync("Error", "玩家不在游戏中");
                return;
            }

            // 获取当前玩家状态
            var currentState = await _playerStateService.GetPlayerStateAsync(gameId, playerId);
            if (currentState == null || currentState.State != PlayerDrawingState.Drawing)
            {
                await Clients.Caller.SendAsync("Error", "玩家未在绘制状态");
                return;
            }

            // 调用领域服务停止绘制
            var drawingResult = await _playerStateService.StopDrawingAsync(
                gameId, playerId, currentState.CurrentPosition);

            if (!drawingResult.Success)
            {
                await Clients.Caller.SendAsync("DrawingFailed", new
                {
                    PlayerId = playerId,
                    Reason = string.Join("; ", drawingResult.Errors),
                    Timestamp = DateTime.UtcNow
                });
                return;
            }

            // 记录完成绘制动作
            var completeAction = GameAction.CreateCompleteTerritory(
                gameId: gameId,
                userId: playerId,
                x: (decimal)(drawingResult.CompletedTrail.LastOrDefault()?.X ?? 0),
                y: (decimal)(drawingResult.CompletedTrail.LastOrDefault()?.Y ?? 0),
                areaGained: (decimal)drawingResult.AreaGained,
                territoryData: $"{{\"path\":[{string.Join(",", drawingResult.CompletedTrail.Select(p => p.ToString()))}],\"isClosedLoop\":{drawingResult.IsClosedLoop.ToString().ToLower()}}}",
                timestamp: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            );

            await _gameActionRepository.AddAsync(completeAction);

            // 如果成功获得新领土，计算并更新排名
            if (drawingResult.NewTerritory != null && drawingResult.AreaGained > 0)
            {
                var territoryResult = await _playerStateService.CalculatePlayerTerritoryAsync(gameId, playerId);
                if (territoryResult.Success)
                {
                    // 更新游戏排名
                    var rankings = await _playerStateService.GetGameRankingAsync(gameId);
                    
                    // 广播排名更新
                    var groupName = $"game_{gameId}";
                    await Clients.Group(groupName).SendAsync("RankingUpdated", new
                    {
                        Rankings = rankings.Select(r => new
                        {
                            r.PlayerId,
                            r.PlayerName,
                            r.Rank,
                            r.TerritoryArea,
                            r.AreaPercentage
                        }).ToList(),
                        Timestamp = DateTime.UtcNow
                    });
                }
            }
            
            // 实时广播给房间内所有玩家
            var groupName2 = $"game_{gameId}";
            await Clients.Group(groupName2).SendAsync("DrawingCompleted", new
            {
                PlayerId = playerId,
                CompletedTrail = drawingResult.CompletedTrail,
                NewTerritory = drawingResult.NewTerritory,
                AreaGained = drawingResult.AreaGained,
                IsClosedLoop = drawingResult.IsClosedLoop,
                Messages = drawingResult.Messages,
                Timestamp = DateTime.UtcNow
            });

            _logger.LogInformation("玩家 {PlayerId} 在游戏 {GameId} 中完成路径绘制，获得面积: {Area}", 
                playerId, gameId, drawingResult.AreaGained);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "完成绘制时发生错误: GameId={GameId}, PlayerId={PlayerId}", gameId, playerId);
            await Clients.Caller.SendAsync("Error", "完成绘制失败");
        }
    }

    /// <summary>
    /// 玩家使用道具 - 完整业务逻辑版本
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="playerId">玩家ID</param>
    /// <param name="itemType">道具类型</param>
    /// <param name="targetPlayerId">目标玩家ID（如果需要）</param>
    public async Task UseItem(Guid gameId, Guid playerId, DrawingGameItemType itemType, Guid? targetPlayerId = null)
    {
        try
        {
            // 验证游戏状态
            var game = await _gameRepository.GetByIdAsync(gameId);
            if (game?.Status != GameStatus.Playing)
            {
                await Clients.Caller.SendAsync("Error", "游戏未进行中");
                return;
            }

            // 验证玩家是否在游戏中
            var gamePlayer = (await _gamePlayerRepository.GetAllAsync())
                .FirstOrDefault(gp => gp.GameId == gameId && gp.UserId == playerId);
            
            if (gamePlayer == null)
            {
                await Clients.Caller.SendAsync("Error", "玩家不在游戏中");
                return;
            }

            // 获取当前玩家状态
            var currentState = await _playerStateService.GetPlayerStateAsync(gameId, playerId);
            if (currentState == null || currentState.State == PlayerDrawingState.Dead)
            {
                await Clients.Caller.SendAsync("Error", "玩家状态异常或已死亡");
                return;
            }

            // 调用领域服务使用道具
            var useResult = await _playerStateService.UseItemAsync(
                gameId, playerId, itemType, currentState.CurrentPosition);

            if (!useResult.Success)
            {
                await Clients.Caller.SendAsync("ItemUseFailed", new
                {
                    PlayerId = playerId,
                    ItemType = itemType.ToString(),
                    Reason = string.Join("; ", useResult.Errors),
                    Timestamp = DateTime.UtcNow
                });
                return;
            }

            // 记录使用道具动作
            var effectData = useResult.AppliedEffect != null ? 
                $"{{\"effectType\":\"{useResult.AppliedEffect.EffectType}\",\"duration\":{useResult.AppliedEffect.Duration.TotalSeconds}}}" : "null";
            var itemAction = GameAction.CreateUsePowerUpAction(
                gameId: gameId,
                userId: playerId,
                x: 0, // 道具使用可能没有具体坐标
                y: 0,
                powerUpType: itemType.ToString(),
                effect: $"{{\"targetPlayerId\":\"{targetPlayerId}\",\"appliedEffect\":{effectData},\"messages\":[{string.Join(",", useResult.Messages.Select(m => $"\"{m}\""))}]}}",
                timestamp: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
            );

            await _gameActionRepository.AddAsync(itemAction);

            // 实时广播给房间内所有玩家
            var groupName = $"game_{gameId}";
            await Clients.Group(groupName).SendAsync("ItemUsed", new
            {
                PlayerId = playerId,
                ItemType = itemType.ToString(),
                TargetPlayerId = targetPlayerId,
                AppliedEffect = useResult.AppliedEffect,
                ClearedTrails = useResult.ClearedTrails,
                AffectedPlayers = useResult.AffectedPlayers,
                TargetPosition = useResult.TargetPosition,
                Messages = useResult.Messages,
                Timestamp = DateTime.UtcNow
            });

            // 如果道具影响其他玩家，单独通知目标玩家
            if (targetPlayerId.HasValue && useResult.AffectedPlayers?.Contains(targetPlayerId.Value) == true)
            {
                // 这里需要根据连接管理来找到目标玩家的ConnectionId
                // 简化处理：通过组广播，让客户端自己判断
                await Clients.Group(groupName).SendAsync("PlayerAffectedByItem", new
                {
                    AffectedPlayerId = targetPlayerId.Value,
                    SourcePlayerId = playerId,
                    ItemType = itemType.ToString(),
                    AppliedEffect = useResult.AppliedEffect,
                    Messages = useResult.Messages,
                    Timestamp = DateTime.UtcNow
                });
            }

            _logger.LogInformation("玩家 {PlayerId} 在游戏 {GameId} 中使用道具 {ItemType}, 目标: {TargetPlayerId}, 消息: {Messages}",
                playerId, gameId, itemType, targetPlayerId, string.Join("; ", useResult.Messages));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "使用道具时发生错误: GameId={GameId}, PlayerId={PlayerId}, ItemType={ItemType}",
                gameId, playerId, itemType);
            await Clients.Caller.SendAsync("Error", "使用道具失败");
        }
    }

    /// <summary>
    /// 连接断开时的处理
    /// </summary>
    /// <param name="exception">异常信息</param>
    /// <returns></returns>
    public override async Task OnDisconnectedAsync(Exception? exception)
    {
        try
        {
            // TODO: 从上下文中获取玩家信息并处理断线
            // 这里可以根据ConnectionId查找对应的玩家并通知其他玩家
            
            _logger.LogInformation("连接 {ConnectionId} 断开", Context.ConnectionId);
            
            if (exception != null)
            {
                _logger.LogWarning(exception, "连接 {ConnectionId} 异常断开", Context.ConnectionId);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理连接断开时发生错误: ConnectionId={ConnectionId}", Context.ConnectionId);
        }

        await base.OnDisconnectedAsync(exception);
    }

    /// <summary>
    /// 连接建立时的处理
    /// </summary>
    /// <returns></returns>
    public override async Task OnConnectedAsync()
    {
        try
        {
            _logger.LogInformation("新连接建立: {ConnectionId}", Context.ConnectionId);
            await Clients.Caller.SendAsync("Connected", new { ConnectionId = Context.ConnectionId });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理连接建立时发生错误: ConnectionId={ConnectionId}", Context.ConnectionId);
        }

        await base.OnConnectedAsync();
    }

    /// <summary>
    /// 处理碰撞事件 - 内部辅助方法
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="playerId">玩家ID</param>
    /// <param name="collisionInfo">碰撞信息</param>
    private async Task HandleCollisionEventAsync(Guid gameId, Guid playerId, PlayerCollisionInfo collisionInfo)
    {
        try
        {
            var groupName = $"game_{gameId}";
            
            // 根据碰撞类型处理
            switch (collisionInfo.Type)
            {
                case DrawingGameCollisionType.TrailCollision:
                    // 轨迹碰撞 - 玩家死亡
                    var collisionResult = await _playerStateService.HandleTrailCollisionAsync(
                        gameId, playerId, collisionInfo.CollisionPoint, collisionInfo.OtherPlayerId);
                    
                    if (collisionResult.PlayerDied)
                    {
                        await Clients.Group(groupName).SendAsync("PlayerDied", new
                        {
                            DeadPlayerId = playerId,
                            KillerId = collisionResult.KillerId,
                            KillerName = collisionResult.KillerName,
                            DeathReason = collisionResult.DeathReason,
                            CollisionPoint = collisionInfo.CollisionPoint,
                            ClearedTrail = collisionResult.ClearedTrail,
                            Timestamp = DateTime.UtcNow
                        });

                        _logger.LogInformation("玩家 {PlayerId} 在游戏 {GameId} 中死亡: {Reason}", 
                            playerId, gameId, collisionResult.DeathReason);
                    }
                    break;

                case DrawingGameCollisionType.TerritoryEntry:
                    // 进入领地 - 仅通知
                    await Clients.Group(groupName).SendAsync("PlayerEnteredTerritory", new
                    {
                        PlayerId = playerId,
                        TerritoryOwnerId = collisionInfo.OtherPlayerId,
                        EntryPoint = collisionInfo.CollisionPoint,
                        Timestamp = DateTime.UtcNow
                    });
                    break;

                case DrawingGameCollisionType.BoundaryHit:
                    // 边界碰撞 - 阻止移动
                    await Clients.Caller.SendAsync("BoundaryHit", new
                    {
                        PlayerId = playerId,
                        HitPoint = collisionInfo.CollisionPoint,
                        Timestamp = DateTime.UtcNow
                    });
                    break;

                case DrawingGameCollisionType.ObstacleHit:
                    // 障碍物碰撞 - 阻止移动
                    await Clients.Caller.SendAsync("ObstacleHit", new
                    {
                        PlayerId = playerId,
                        HitPoint = collisionInfo.CollisionPoint,
                        ObstacleId = collisionInfo.OtherPlayerId, // 这里用作障碍物ID
                        Timestamp = DateTime.UtcNow
                    });
                    break;
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理碰撞事件时发生错误: GameId={GameId}, PlayerId={PlayerId}", gameId, playerId);
        }
    }

    #region 高级游戏机制实时通信

    /// <summary>
    /// 触发特殊事件广播
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="eventType">事件类型</param>
    public async Task TriggerSpecialEvent(Guid gameId, string eventType)
    {
        try
        {
            _logger.LogInformation("触发特殊事件: GameId={GameId}, EventType={EventType}", gameId, eventType);

            // 广播特殊事件给房间内所有玩家
            await Clients.Group($"Game_{gameId}").SendAsync("SpecialEventTriggered", new
            {
                GameId = gameId,
                EventType = eventType,
                Message = $"特殊事件'{eventType}'已触发！",
                Timestamp = DateTime.UtcNow
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "触发特殊事件时发生错误: GameId={GameId}, EventType={EventType}", gameId, eventType);
        }
    }

    /// <summary>
    /// 广播动态平衡调整
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="playerId">受影响的玩家ID</param>
    /// <param name="balanceType">平衡类型</param>
    /// <param name="effectDescription">效果描述</param>
    public async Task BroadcastBalanceAdjustment(Guid gameId, Guid playerId, string balanceType, string effectDescription)
    {
        try
        {
            _logger.LogInformation("广播动态平衡调整: GameId={GameId}, PlayerId={PlayerId}, BalanceType={BalanceType}", 
                gameId, playerId, balanceType);

            // 向特定玩家发送平衡调整通知
            await Clients.Group($"Game_{gameId}").SendAsync("BalanceAdjustmentApplied", new
            {
                GameId = gameId,
                PlayerId = playerId,
                BalanceType = balanceType,
                EffectDescription = effectDescription,
                Timestamp = DateTime.UtcNow
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播动态平衡调整时发生错误: GameId={GameId}, PlayerId={PlayerId}", gameId, playerId);
        }
    }

    /// <summary>
    /// 广播地图缩圈开始
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="shrinkingInfo">缩圈信息</param>
    public async Task BroadcastMapShrinkingStart(Guid gameId, object shrinkingInfo)
    {
        try
        {
            _logger.LogInformation("广播地图缩圈开始: GameId={GameId}", gameId);

            // 向房间内所有玩家广播缩圈开始
            await Clients.Group($"Game_{gameId}").SendAsync("MapShrinkingStarted", new
            {
                GameId = gameId,
                Message = "⚠️ 地图开始缩圈！请尽快向安全区域移动！",
                ShrinkingInfo = shrinkingInfo,
                Timestamp = DateTime.UtcNow
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播地图缩圈开始时发生错误: GameId={GameId}", gameId);
        }
    }

    /// <summary>
    /// 广播地图缩圈更新
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="shrinkingStatus">缩圈状态</param>
    public async Task BroadcastMapShrinkingUpdate(Guid gameId, object shrinkingStatus)
    {
        try
        {
            _logger.LogDebug("广播地图缩圈更新: GameId={GameId}", gameId);

            // 定期更新缩圈状态
            await Clients.Group($"Game_{gameId}").SendAsync("MapShrinkingUpdate", new
            {
                GameId = gameId,
                ShrinkingStatus = shrinkingStatus,
                Timestamp = DateTime.UtcNow
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播地图缩圈更新时发生错误: GameId={GameId}", gameId);
        }
    }

    /// <summary>
    /// 通知玩家进入危险区域
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="playerId">玩家ID</param>
    /// <param name="dangerLevel">危险级别</param>
    public async Task NotifyPlayerInDangerZone(Guid gameId, Guid playerId, float dangerLevel)
    {
        try
        {
            _logger.LogWarning("玩家进入危险区域: GameId={GameId}, PlayerId={PlayerId}, DangerLevel={DangerLevel}", 
                gameId, playerId, dangerLevel);

            // 向特定玩家发送危险区域警告
            await Clients.Group($"Game_{gameId}").SendAsync("PlayerInDangerZone", new
            {
                GameId = gameId,
                PlayerId = playerId,
                DangerLevel = dangerLevel,
                Message = dangerLevel > 0.8f ? "🚨 您在极度危险区域！" : "⚠️ 您在危险区域内，正在受到伤害！",
                Timestamp = DateTime.UtcNow
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "通知玩家危险区域时发生错误: GameId={GameId}, PlayerId={PlayerId}", gameId, playerId);
        }
    }

    /// <summary>
    /// 广播橡皮筋联盟形成
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    /// <param name="allianceMembers">联盟成员</param>
    public async Task BroadcastRubberBandAlliance(Guid gameId, List<Guid> allianceMembers)
    {
        try
        {
            _logger.LogInformation("广播橡皮筋联盟形成: GameId={GameId}, MemberCount={MemberCount}", 
                gameId, allianceMembers.Count);

            // 向房间内所有玩家广播联盟形成
            await Clients.Group($"Game_{gameId}").SendAsync("RubberBandAllianceFormed", new
            {
                GameId = gameId,
                AllianceMembers = allianceMembers,
                Message = $"🤝 橡皮筋联盟已形成！{allianceMembers.Count}名落后玩家获得轨迹免疫",
                Timestamp = DateTime.UtcNow
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播橡皮筋联盟时发生错误: GameId={GameId}", gameId);
        }
    }

    /// <summary>
    /// 实时游戏状态同步（包含高级机制状态）
    /// </summary>
    /// <param name="gameId">游戏ID</param>
    public async Task SyncAdvancedGameState(Guid gameId)
    {
        try
        {
            _logger.LogDebug("同步高级游戏状态: GameId={GameId}", gameId);

            // 获取所有高级机制的当前状态
            var specialEvents = await _specialEventService.GetActiveEventsAsync(gameId);
            var shrinkingStatus = await _mapShrinkingService.GetShrinkingStatusAsync(gameId);
            
            // 构建完整的高级状态信息
            var advancedState = new
            {
                GameId = gameId,
                SpecialEvents = new
                {
                    ActiveEvents = specialEvents.Take(5).Select(e => new { e.EventType, e.EventName, e.RemainingSeconds }),
                    EventCount = specialEvents.Count
                },
                MapShrinking = new
                {
                    IsShrinking = shrinkingStatus.IsShrinking,
                    Phase = shrinkingStatus.Phase.ToString(),
                    Progress = shrinkingStatus.Progress,
                    RemainingSeconds = shrinkingStatus.RemainingSeconds
                },
                Timestamp = DateTime.UtcNow
            };

            // 广播高级状态给房间内所有玩家
            await Clients.Group($"Game_{gameId}").SendAsync("AdvancedGameStateUpdate", advancedState);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "同步高级游戏状态时发生错误: GameId={GameId}", gameId);
        }
    }

    #endregion

    #region 房间聊天实时通信

    /// <summary>
    /// 加入房间聊天
    /// </summary>
    /// <param name="roomId">房间ID</param>
    public async Task JoinRoomChat(Guid roomId)
    {
        try
        {
            _logger.LogInformation("[调试] JoinRoomChat 开始 - RoomId: {RoomId}, ConnectionId: {ConnectionId}", roomId, Context.ConnectionId);
            
            var userId = GetCurrentUserId();
            _logger.LogInformation("[调试] 获取当前用户ID - UserId: {UserId}", userId);
            
            if (userId == Guid.Empty)
            {
                _logger.LogWarning("[调试] 用户未认证 - RoomId: {RoomId}", roomId);
                await Clients.Caller.SendAsync("Error", "用户未认证");
                return;
            }

            // 验证用户是否在房间中
            _logger.LogInformation("[调试] 开始验证用户是否在房间中 - RoomId: {RoomId}, UserId: {UserId}", roomId, userId);
            var roomPlayer = await _roomPlayerRepository.GetSingleAsync(rp => rp.RoomId == roomId && rp.UserId == userId);
            _logger.LogInformation("[调试] 房间成员查询结果 - RoomPlayer: {RoomPlayer}", roomPlayer != null ? $"Found(UserId={roomPlayer.UserId}, IsReady={roomPlayer.IsReady})" : "NULL");
            
            if (roomPlayer == null)
            {
                _logger.LogWarning("[调试] 用户不在房间中 - RoomId: {RoomId}, UserId: {UserId}", roomId, userId);
                await Clients.Caller.SendAsync("Error", "您不在该房间中");
                return;
            }

            // 加入SignalR组
            var roomGroupName = $"room_chat_{roomId}";
            _logger.LogInformation("[调试] 开始加入SignalR组 - GroupName: {GroupName}, ConnectionId: {ConnectionId}", roomGroupName, Context.ConnectionId);
            await Groups.AddToGroupAsync(Context.ConnectionId, roomGroupName);
            _logger.LogInformation("[调试] 成功加入SignalR组 - GroupName: {GroupName}", roomGroupName);

            // 获取用户信息
            var user = await _userRepository.GetByIdAsync(userId);
            var username = user?.Username ?? "未知用户";
            _logger.LogInformation("[调试] 获取用户信息 - Username: {Username}", username);

            // 如果是正式房间成员，通知其他用户
            if (roomPlayer != null)
            {
                _logger.LogInformation("[调试] 向房间组广播用户加入事件 - GroupName: {GroupName}, Username: {Username}", roomGroupName, username);
                await Clients.Group(roomGroupName).SendAsync("UserJoinedRoomChat", new
                {
                    UserId = userId,
                    Username = username,
                    RoomId = roomId,
                    ConnectionId = Context.ConnectionId,
                    JoinedAt = DateTime.UtcNow
                });
            }

            // 确认加入成功
            _logger.LogInformation("[调试] 向调用者发送加入成功确认 - RoomId: {RoomId}", roomId);
            await Clients.Caller.SendAsync("RoomChatJoined", new
            {
                RoomId = roomId,
                Message = "已加入房间聊天",
                IsMember = roomPlayer != null,
                Timestamp = DateTime.UtcNow
            });

            _logger.LogInformation("[调试] JoinRoomChat 完成 - 用户 {UserId}({Username}) 成功加入房间 {RoomId} 的聊天", userId, username, roomId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "用户加入房间聊天时发生错误: RoomId={RoomId}", roomId);
            await Clients.Caller.SendAsync("Error", "加入房间聊天失败");
        }
    }

    /// <summary>
    /// 离开房间聊天
    /// </summary>
    /// <param name="roomId">房间ID</param>
    public async Task LeaveRoomChat(Guid roomId)
    {
        try
        {
            var userId = GetCurrentUserId();
            if (userId == Guid.Empty)
            {
                return;
            }

            var roomGroupName = $"room_chat_{roomId}";
            await Groups.RemoveFromGroupAsync(Context.ConnectionId, roomGroupName);

            // 获取用户信息
            var user = await _userRepository.GetByIdAsync(userId);
            var username = user?.Username ?? "未知用户";

            // 通知房间内其他用户
            await Clients.Group(roomGroupName).SendAsync("UserLeftRoomChat", new
            {
                UserId = userId,
                Username = username,
                RoomId = roomId,
                ConnectionId = Context.ConnectionId,
                LeftAt = DateTime.UtcNow
            });

            _logger.LogInformation("用户 {UserId}({Username}) 离开房间 {RoomId} 的聊天", userId, username, roomId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "用户离开房间聊天时发生错误: RoomId={RoomId}", roomId);
        }
    }

    /// <summary>
    /// 发送房间聊天消息（实时广播）
    /// </summary>
    /// <param name="roomId">房间ID</param>
    /// <param name="message">消息内容</param>
    /// <param name="messageType">消息类型</param>
    public async Task SendRoomChatMessage(Guid roomId, string message, string messageType = "text")
    {
        try
        {
            var userId = GetCurrentUserId();
            if (userId == Guid.Empty)
            {
                await Clients.Caller.SendAsync("Error", "用户未认证");
                return;
            }

            // 调用房间服务发送消息（存储到数据库）
            var result = await _roomService.SendChatMessageAsync(roomId, userId, message, messageType);

            if (!result.Success)
            {
                await Clients.Caller.SendAsync("ChatMessageFailed", new
                {
                    RoomId = roomId,
                    Message = result.Message,
                    Errors = result.Errors,
                    Timestamp = DateTime.UtcNow
                });
                return;
            }

            // 实时广播给房间内所有用户
            var roomGroupName = $"room_chat_{roomId}";
            await Clients.Group(roomGroupName).SendAsync("NewChatMessage", new
            {
                Id = result.MessageInfo!.Id,
                RoomId = result.MessageInfo.RoomId,
                UserId = result.MessageInfo.UserId,
                Username = result.MessageInfo.Username,
                Message = result.MessageInfo.Message,
                MessageType = result.MessageInfo.MessageType,
                CreatedAt = result.MessageInfo.CreatedAt,
                IsRealtime = true, // 标识为实时消息
                Timestamp = DateTime.UtcNow
            });

            // 确认发送成功
            await Clients.Caller.SendAsync("ChatMessageSent", new
            {
                MessageId = result.MessageInfo.Id,
                RoomId = roomId,
                Message = "消息发送成功",
                Timestamp = DateTime.UtcNow
            });

            _logger.LogDebug("用户 {UserId} 在房间 {RoomId} 发送聊天消息: {Message}", 
                userId, roomId, message.Length > 50 ? $"{message.Substring(0, 47)}..." : message);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送房间聊天消息时发生错误: RoomId={RoomId}", roomId);
            await Clients.Caller.SendAsync("Error", "发送消息失败");
        }
    }

    /// <summary>
    /// 广播系统消息到房间
    /// </summary>
    /// <param name="roomId">房间ID</param>
    /// <param name="systemMessage">系统消息</param>
    public async Task BroadcastRoomSystemMessage(Guid roomId, string systemMessage)
    {
        try
        {
            var roomGroupName = $"room_chat_{roomId}";
            
            // 发送系统消息给房间内所有用户
            await Clients.Group(roomGroupName).SendAsync("SystemMessage", new
            {
                RoomId = roomId,
                Message = systemMessage,
                MessageType = "system",
                CreatedAt = DateTime.UtcNow,
                Timestamp = DateTime.UtcNow
            });

            _logger.LogInformation("广播系统消息到房间 {RoomId}: {Message}", roomId, systemMessage);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播系统消息时发生错误: RoomId={RoomId}", roomId);
        }
    }

    /// <summary>
    /// 广播房间状态变化
    /// </summary>
    /// <param name="roomId">房间ID</param>
    /// <param name="statusChange">状态变化信息</param>
    public async Task BroadcastRoomStatusChange(Guid roomId, object statusChange)
    {
        try
        {
            var roomGroupName = $"room_chat_{roomId}";
            
            await Clients.Group(roomGroupName).SendAsync("RoomStatusChanged", new
            {
                RoomId = roomId,
                StatusChange = statusChange,
                Timestamp = DateTime.UtcNow
            });

            _logger.LogInformation("广播房间状态变化到房间 {RoomId}", roomId);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "广播房间状态变化时发生错误: RoomId={RoomId}", roomId);
        }
    }

    /// <summary>
    /// 通知用户加入房间
    /// </summary>
    /// <param name="roomId">房间ID</param>
    /// <param name="userId">加入的用户ID</param>
    /// <param name="username">用户名</param>
    public async Task NotifyUserJoinedRoom(Guid roomId, Guid userId, string username)
    {
        try
        {
            var roomGroupName = $"room_chat_{roomId}";
            
            await Clients.Group(roomGroupName).SendAsync("UserJoinedRoom", new
            {
                RoomId = roomId,
                UserId = userId,
                Username = username,
                Message = $"{username} 加入了房间",
                MessageType = "system",
                Timestamp = DateTime.UtcNow
            });

            _logger.LogInformation("通知房间 {RoomId} 用户 {Username} 加入", roomId, username);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "通知用户加入房间时发生错误: RoomId={RoomId}, UserId={UserId}", roomId, userId);
        }
    }

    /// <summary>
    /// 通知用户离开房间
    /// </summary>
    /// <param name="roomId">房间ID</param>
    /// <param name="userId">离开的用户ID</param>
    /// <param name="username">用户名</param>
    public async Task NotifyUserLeftRoom(Guid roomId, Guid userId, string username)
    {
        try
        {
            var roomGroupName = $"room_chat_{roomId}";
            
            await Clients.Group(roomGroupName).SendAsync("UserLeftRoom", new
            {
                RoomId = roomId,
                UserId = userId,
                Username = username,
                Message = $"{username} 离开了房间",
                MessageType = "system",
                Timestamp = DateTime.UtcNow
            });

            _logger.LogInformation("通知房间 {RoomId} 用户 {Username} 离开", roomId, username);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "通知用户离开房间时发生错误: RoomId={RoomId}, UserId={UserId}", roomId, userId);
        }
    }

    /// <summary>
    /// 通知用户准备状态变化
    /// </summary>
    /// <param name="roomId">房间ID</param>
    /// <param name="userId">用户ID</param>
    /// <param name="username">用户名</param>
    /// <param name="isReady">是否准备</param>
    public async Task NotifyUserReadyStatusChanged(Guid roomId, Guid userId, string username, bool isReady)
    {
        try
        {
            var roomGroupName = $"room_chat_{roomId}";
            
            await Clients.Group(roomGroupName).SendAsync("UserReadyStatusChanged", new
            {
                RoomId = roomId,
                UserId = userId,
                Username = username,
                IsReady = isReady,
                Message = $"{username} {(isReady ? "已准备" : "取消准备")}",
                MessageType = "system",
                Timestamp = DateTime.UtcNow
            });

            _logger.LogInformation("通知房间 {RoomId} 用户 {Username} 准备状态: {IsReady}", roomId, username, isReady);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "通知用户准备状态变化时发生错误: RoomId={RoomId}, UserId={UserId}", roomId, userId);
        }
    }

    /// <summary>
    /// 获取当前用户ID
    /// </summary>
    /// <returns>用户ID，如果未认证返回Guid.Empty</returns>
    private Guid GetCurrentUserId()
    {
        var userIdClaim = Context.User?.FindFirst(ClaimTypes.NameIdentifier);
        return userIdClaim != null && Guid.TryParse(userIdClaim.Value, out var userId) 
            ? userId : Guid.Empty;
    }

    #endregion

}
